《Android 进阶(四)》 自定义View之仿Emui开关控件

1. 简介

使用华为手机,发现设置应用中的开关空间颜色听挺好看,所以自己想写一个类似的,当然不可能完全相同,但是大致的效果差不多。
操作步骤:

  1. 截图。PS取色;
  2. 判断左右两边的半径;
  3. 继承View复写onDraw方法,手动绘制。
  4. 控制开关的状态:on/off

    2. 效果

这里写图片描述

3. 实现

3.1 自定义属性

没有定义,颜色和半径都是按照自己的效果写成固定的,当然也可以写成自定义属性。

3.2 自定义View代码

涉及到一些动画的使用和View的事件处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
public class CustomSwitchView extends View {
/**
* 开关圆点颜色
*/
private final int SWITCH_DOT_COLOR = 0xffffffff;

/**
* 关闭状态下的背景颜色
*/
private final int OFF_BACKGROUND_COLOR = 0xffe2e2e2;

/**
* 打开状态下的背景颜色
*/
private final int ON_BACKGROUND_COLOR = 0xff007dff;

/**
* 边界和开关圆点的间距
*/
private final int BOUND_DOT_GAP = 8;

/**
* 是否打开
*/
private boolean isOn = false;

/**
* 圆点的半径和坐标位置
*/
private int mRadius;

private int startX;
private int endX;
private float centerX;
private float centerY;
private RectF mRectF;

/**
* 开关的画笔
*/
private Paint mSwitchPaint;

public CustomSwitchView(Context context) {
this(context, null);
}

public CustomSwitchView(Context context,
@Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public CustomSwitchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

/**
* 打开或者关闭
*
* @param on true 打开, false 关闭
*/
public void setOn(boolean on) {
isOn = on;
ValueAnimator animator;
if (on) {
animator = ValueAnimator.ofFloat(centerX, endX);
} else {
animator = ValueAnimator.ofFloat(centerX, startX);
}
animator.setDuration(200);
animator.setRepeatCount(0);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
centerX = (Float) animation.getAnimatedValue();
invalidate();
}
});
animator.start();
}

private void init() {
mSwitchPaint = new Paint();
mSwitchPaint.setColor(OFF_BACKGROUND_COLOR);
mSwitchPaint.setStrokeWidth(10f);
mSwitchPaint.setStrokeCap(Paint.Cap.ROUND);
mSwitchPaint.setAntiAlias(true);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRectF = new RectF(getLeft(), getTop(), getRight(), getBottom());
mRadius = h / 2 - BOUND_DOT_GAP;
startX = getLeft() + mRadius + BOUND_DOT_GAP / 2;
endX = getRight() - mRadius - BOUND_DOT_GAP / 2;
centerX = startX;
centerY = (getTop() + getBottom()) / 2.0f;
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isOn) {
mSwitchPaint.setColor(ON_BACKGROUND_COLOR);
} else {
mSwitchPaint.setColor(OFF_BACKGROUND_COLOR);
}
canvas.drawRoundRect(mRectF, mRadius, mRadius, mSwitchPaint);
mSwitchPaint.setColor(SWITCH_DOT_COLOR);
canvas.drawCircle(centerX, centerY, mRadius, mSwitchPaint);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
setOn(!isOn);
break;
case MotionEvent.ACTION_MOVE: {
float x = event.getX();
if (x < endX && x > startX) {
centerX = x;
invalidate();
}
}
break;
default:
break;
}
return true;
}
}

4. 源码

源码依然是上传到Github
CustomViewDemo

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×